package com.sinothk.gpserver.connection.websocket;

import com.alibaba.fastjson.JSON;
import com.sinothk.gpserver.connection.websocket.bean.*;
import com.sinothk.gpserver.connection.websocket.config.ServerEncoder;
import com.sinothk.gpserver.connection.websocket.utils.RoomTool;
import com.sinothk.gpserver.data.WsConstant;
import com.sinothk.gpserver.modules.biz.entity.GroupUserDto;
import com.sinothk.gpserver.modules.texasPoker.helper.TexasPokerCompare;
import com.sinothk.server.support.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 编写 Liang Y.T.
 * 时间 2021/6/24 17:25
 *
 * @ ServerEndpoint 注解是一个类层次的注解，它的功能主要是将目前的类定义成一个websocket服务器端,
 * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
 */
@Component
@Slf4j
@Service
@ServerEndpoint(value = "/socket/{loginId}", encoders = ServerEncoder.class)
public class WebSocketServer extends WebSocketServerBase {

    //静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;
    //concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
//    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();

    public static ConcurrentHashMap<String, Session> webClients = new ConcurrentHashMap<String, Session>();

    //与某个客户端的连接会话，需要通过它来给客户端发送数据
//    private Session session;

    //接收sid
    private String loginId = "";

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

//    public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {
//        return webSocketSet;
//    }

    private static WebSocketServer singObj;

    public static WebSocketServer obj() {
        if (null == singObj) {
            synchronized (WebSocketServer.class) {
                if (null == singObj) {
                    singObj = new WebSocketServer();
                }
            }
        }
        return singObj;
    }

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("loginId") String loginId) {
//        this.session = session;
//        webSocketSet.add(this);     //加入set中
        webClients.put(loginId, session);

        this.loginId = loginId;
        addOnlineCount();           //在线数加1
        try {
            sendMessage(session, JSON.toJSONString(Message.getPersonMsg(new PersonMsg(WsConstant.TYPE_PM.CONN_OPEN))));
            log.info("有新窗口开始监听:" + loginId + ",当前在线人数为:" + getOnlineCount());
        } catch (IOException e) {
            log.error("websocket IO Exception：" + e.getMessage());
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webClients.remove(loginId);  //从set中删除
        subOnlineCount();           //在线数减1

        //断开连接情况下，更新主板占用情况为释放
        log.info("释放的sid为：" + loginId);
        //这里写你 释放的时候，要处理的业务
        log.info("有一连接关闭！当前在线人数为" + getOnlineCount());
    }

    /**
     * @ Param session
     * @ Param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }

    public void sendMessage(Session session, String message) throws IOException {
        session.getBasicRemote().sendText(message);
    }

    // 收到消息 ================================================================================================

    /**
     * 收到客户端消息后调用的方法
     *
     * @ Param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String msg, Session session) {
        if (StringUtils.isEmpty(msg)) {
            return;
        }

        log.info("收到来自窗口" + session.getId() + "的信息:" + msg);
        try {
            msgCenter(JSON.parseObject(msg, Message.class));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void msgCenter(Message msg) {
        switch (msg.getType()) {
            case Message.TYPE_ROOM: {
                // 房间消息
                sendRoomMsg(JSON.parseObject(msg.getBody(), RoomMsg.class));
            }
            case Message.TYPE_PERSON: {

            }
            case Message.TYPE_BROADCAST: {

            }
            case Message.TYPE_GROUP: {

            }
            case Message.TYPE_CLUB: {

            }
        }
    }

    // 发送消息 ================================================================================================
//    public static ConcurrentHashMap<String, ConcurrentHashMap<String, String>> roomUsersMap = new ConcurrentHashMap<>();

    // 房间》所有房间集合<roomNum, room>
    public static ConcurrentHashMap<String, RoomIM> roomsMap = new ConcurrentHashMap<>();

    private void initPlay(RoomIM roomIMForFlow) {
        RoomTool.setNoSpeak(roomIMForFlow);
        RoomTool.setNoPreCast(roomIMForFlow);
    }

    private void msgForRoom(RoomIM roomIM, int type) {
        msgForRoom(roomIM, type, "");
    }

    private void msgForRoom(RoomIM roomIM, int type, String errorInfo) {
        ConcurrentHashMap<String, Visitor> visitors = roomIM.getVisitors();
        // 通知房间里的访客
        for (String key : visitors.keySet()) {
            Session sessionJoin = webClients.get(key);
            if (sessionJoin == null) {
                continue;
            }

            try {
                // 房间消息
                RoomMsg roomBack = new RoomMsg();
                roomBack.setRoomNum(roomIM.getRoomNum());
                roomBack.setType(type);
                roomBack.setBody(JSON.toJSONString(roomIM));
                roomBack.setErrorInfo(errorInfo);
                // 消息
                Message message = new Message();
                message.setType(WsConstant.MsgType.TYPE_ROOM);
                message.setBody(JSON.toJSONString(roomBack));

                log.error("返回当前房间信息给访客" + JSON.toJSONString(roomBack));
                // 发送
                sessionJoin.getBasicRemote().sendObject(message);
            } catch (IOException | EncodeException ioException) {
                ioException.printStackTrace();
            }
        }
    }

    private void msgForRoomError(int type, String[] accountArr, String errorInfo) {
//        ConcurrentHashMap<String, Visitor> visitors = roomIM.getVisitors();
        // 通知房间里的访客
        for (String key : accountArr) {
            Session sessionJoin = webClients.get(key);
            if (sessionJoin == null) {
                continue;
            }

            try {
                // 房间消息
                RoomMsg roomBack = new RoomMsg();
//                roomBack.setRoomNum(roomIM.getRoomNum());
                roomBack.setType(type);
//                roomBack.setBody(JSON.toJSONString(roomIM));
                roomBack.setErrorInfo(errorInfo);
                // 消息
                Message message = new Message();
                message.setType(WsConstant.MsgType.TYPE_ROOM);
                message.setBody(JSON.toJSONString(roomBack));

                log.error("返回当前房间信息给访客" + JSON.toJSONString(roomBack));
                // 发送
                sessionJoin.getBasicRemote().sendObject(message);
            } catch (IOException | EncodeException ioException) {
                ioException.printStackTrace();
            }
        }
    }

    private void timerStart(RoomIM roomIM) {
        int time = 5;
        while (time > 0) {
            try {
                Thread.sleep(1000);

                System.out.println("还剩" + time);
                if (time <= 1) {
                    if (roomIM.getGameTimes() < roomIM.getGameSize()) {
                        restart(roomIM);
                        time = 0;
                    } else {
                        deleteRoom(roomIM);
                        time = 0;
                    }
                    break;
                }

                time--;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    private void deleteRoom(RoomIM roomIM) {
        // 格式化Room信息   临时
        RoomTool.resetRoom(roomIM);

        String roomNum = roomIM.getRoomNum();

        // 删除房间 DB
        roomService.removeRoom(roomNum);
        // 删除房间 IM
        msgForRoom(RoomTool.getBackRoomByRoom(roomIM), WsConstant.TYPE_RM.TYPE_ROOM_RELEASE_BACK);
        log.error("解散房间" + roomNum);
        roomsMap.remove(roomNum);
    }

    private void errorMsg(RoomIM roomIM, String errorInfo) {
        // 所有错误信息
        msgForRoom(RoomTool.getBackRoomByRoom(roomIM), WsConstant.TYPE_RM.TYPE_ROOM_ALL_ERROR_BACK, errorInfo);
    }

    private void errorMsgForSingle(String[] userAcc, String errorInfo) {
        // 所有错误信息
        msgForRoomError(WsConstant.TYPE_RM.TYPE_ROOM_ALL_ERROR_BACK, userAcc, errorInfo);
    }

    private void restart(RoomIM roomIM) {
        doStartRoom(roomIM.getRoomNum());
    }

    private void checkUserCoinsEnable(RoomIM roomIM) {
        // 检查每个用户积分情况，你满足条件提醒
        ConcurrentHashMap<String, Player> players = roomIM.getPlayers();

        for (Map.Entry<String, Player> item : players.entrySet()) {
            String seatNum = item.getKey();
            Player player = item.getValue();

            try {
                if (StringUtils.isEmpty(player.getAccount())) {
                    continue;
                }

                GroupUserDto groupUser = groupMemberService.getGroupMemberByRoomNumAndAccount(roomIM.getRoomNum(), player.getAccount());
                if (groupUser == null) {
                    String[] users = new String[1];
                    users[0] = player.getAccount();
                    errorMsgForSingle(users, "找不到你的信息");
                    continue;
                }

                // 所有人必须大于大盲值
                if (groupUser.getOwnCoins() < roomIM.getBigCast()) {  // 判断积分是否 大于等于 大盲下注值
                    // 从玩家集合中移除积分不足的玩家。
                    roomIM.getPlayers().remove(seatNum);

                    // 更新现有集合
                    roomsMap.put(roomIM.getRoomNum(), roomIM);

                    // 发出最新房间信息
                    msgForRoom(RoomTool.getBackRoomByRoom(roomIM), WsConstant.TYPE_RM.TYPE_ROOM_START_BACK);

                    // 通知当前人员
                    String[] users = new String[1];
                    users[0] = player.getAccount();
                    errorMsgForSingle(users, "您的积分不足，请先充值");
                }
            } catch (Exception e) {
                String[] users = new String[1];
                users[0] = player.getAccount();
                errorMsgForSingle(users, e.getMessage());
                e.printStackTrace();
                return;
            }

        }
    }

    private boolean checkStartEnable(RoomIM roomIM) {
        int realPlay = 0;
        for (Map.Entry<String, Player> item : roomIM.getPlayers().entrySet()) {
            Player player = item.getValue();
            if (player != null && StringUtils.isNotEmpty(player.getAccount()) && player.getOwnCoins() >= roomIM.getBigCast()) {
                realPlay += 1;
            }
        }
        return realPlay > 1;
    }

    /**
     * 发送房间相关信息
     *
     * @param roomMsg
     */
    private void sendRoomMsg(RoomMsg roomMsg) {
        if (webClients == null) {
            log.error(roomMsg.getAccount() + "webClients = null");
            return;
        }

        switch (roomMsg.getType()) {
            case WsConstant.TYPE_RM.TYPE_ROOM_ENTER:
                RoomIM currRoomIM = roomsMap.get(roomMsg.getRoomNum());
                if (currRoomIM == null) {
                    log.error("TYPE_ROOM_ENTER, 房间" + roomMsg.getRoomNum() + "不存在...");
                    return;
                }

                // 将此人加入访客集合
                currRoomIM.getVisitors().put(roomMsg.getAccount(), new Visitor(roomMsg.getAccount()));

                // 保存

                // 更新RoomIm，群发
                roomsMap.put(roomMsg.getRoomNum(), currRoomIM);
                msgForRoom(roomsMap.get(roomMsg.getRoomNum()), WsConstant.TYPE_RM.TYPE_ROOM_ENTER_BACK);
                break;

            case WsConstant.TYPE_RM.TYPE_ROOM_EXIT:
                // 将此人移除访客集合
                RoomIM currRoomExit = roomsMap.get(roomMsg.getRoomNum());
                if (currRoomExit == null) return;

                currRoomExit.getVisitors().remove(roomMsg.getAccount());

                ConcurrentHashMap<String, Player> players = currRoomExit.getPlayers();
                if (players != null && players.size() > 0) {
                    for (Map.Entry<String, Player> entry : players.entrySet()) {
                        if (roomMsg.getAccount().equals(entry.getValue().getAccount())) {
                            currRoomExit.getPlayers().remove(entry.getKey());
                        }
                    }
                }

                log.error(roomMsg.getAccount() + "离开房间" + roomMsg.getRoomNum());
                // 群发
                msgForRoom(roomsMap.get(roomMsg.getRoomNum()), WsConstant.TYPE_RM.TYPE_ROOM_EXIT_BACK);
                break;

            case WsConstant.TYPE_RM.TYPE_ROOM_RELEASE:
                // 将此人移除访客集合
                RoomIM currRoomRelease = roomsMap.get(roomMsg.getRoomNum());
                if (currRoomRelease == null) return;
                deleteRoom(currRoomRelease);
                break;

            case WsConstant.TYPE_RM.TYPE_ROOM_SIT_DOWN:
                sitDown(roomMsg);
                break;

            case WsConstant.TYPE_RM.TYPE_ROOM_START:
                doStartRoom(roomMsg.getRoomNum());
                break;

            case WsConstant.TYPE_RM.TYPE_ROOM_PLAYING_CANCEL:// 弃牌
                giveUpCard(roomMsg);
                break;

            case WsConstant.TYPE_RM.TYPE_ROOM_PLAYING_FLOW:
                // 跟注
                doFlow(roomMsg);
                break;

            case WsConstant.TYPE_RM.TYPE_ROOM_PLAYING_SEE_CARD:
                // 看牌
                doSee(roomMsg);
                break;

            case WsConstant.TYPE_RM.TYPE_ROOM_PLAYING_ADD:// 加注
                doAdd(roomMsg);
                break;
        }
    }

    private void sitDown(RoomMsg roomMsg) {
        RoomIM roomIMSeat = roomsMap.get(roomMsg.getRoomNum());
        // 新增预备人
        GroupUserDto groupUser = null;
        try {
            groupUser = groupMemberService.getGroupMemberByRoomNumAndAccount(roomIMSeat.getRoomNum(), roomMsg.getAccount());
            if (groupUser == null) throw new Exception("找不到对应成员信息");
            if (groupUser.getOwnCoins() < roomIMSeat.getBigCast()) throw new Exception("您的积分不足，请先充值");
        } catch (Exception e) {
            String[] userAcc = new String[1];
            userAcc[0] = roomMsg.getAccount();
            errorMsgForSingle(userAcc, e.getMessage());
            e.printStackTrace();
            return;
        }

        Player player = new Player();//JSON.parseObject(room.getBody(), Player.class);
        // 消息数据
        player.setRunState(WsConstant.PLAYER_RUN.preparer);
        player.setSeatNum(roomMsg.getSeatNum());
        // 查数据库
        player.setOwnCoins(groupUser.getOwnCoins());
        player.setAccount(groupUser.getAccount());
        player.setPlayerName(groupUser.getUserName());
        player.setPlayerAvatar(groupUser.getUserAvatar());

        // 更新im数据
        roomIMSeat.getPlayers().put(player.getSeatNum(), player);

        if (StringUtil.isEmpty(roomIMSeat.getMinCastNo())) {
            roomIMSeat.setMinCastNo(player.getSeatNum());
        }

        // 不足9人，则填充空数据
        RoomTool.addNullPlayer(roomIMSeat);

        // 更新RoomIm，群发
        roomsMap.put(roomMsg.getRoomNum(), roomIMSeat);
        msgForRoom(RoomTool.getBackRoomByRoom(roomIMSeat), WsConstant.TYPE_RM.TYPE_ROOM_SIT_DOWN_BACK);
    }

    private void doStartRoom(String roomNum) {
        RoomIM roomIMStart = roomsMap.get(roomNum);
        if (roomIMStart.getRoomType() == 0) {
            // 格式化Room信息
            RoomTool.resetRoom(roomIMStart);

            // 合并入座人和游戏中的人
            RoomTool.createPlayers(roomIMStart);

            // 检查用户资格,不满足则剔除用户
            checkUserCoinsEnable(roomIMStart);

            // 判断有效用户数
            if (!checkStartEnable(roomIMStart)) {
                // 通知所有人
                msgForRoom(RoomTool.getBackRoomByRoom(roomIMStart), WsConstant.TYPE_RM.TYPE_ROOM_ALL_ERROR_BACK, "人数不足2人，不能开局!");

                // 临时
                roomIMStart.getPlayers().clear();
                roomsMap.put(roomNum, roomIMStart);
                msgForRoom(RoomTool.getBackRoomByRoom(roomIMStart), WsConstant.TYPE_RM.TYPE_ROOM_START_BACK);

                // 人数不足，删除房间
                deleteRoom(roomIMStart);
                return;
            }

            // 给玩家发底牌
            TexasIm.sendPersonCard(roomIMStart);

            // 无人位置处填充空数值
            RoomTool.addNullPlayer(roomIMStart);

            // 更新现有玩家
            RoomTool.refreshCanSpeakPlayerSeat(roomIMStart);

            // 全部设置为未说话
            RoomTool.setNoSpeak(roomIMStart);

            // 自动更新下一次询问位置
            RoomTool.startRecycle(roomIMStart);

            // 扣除 大盲和小盲玩家的 积分
            RoomTool.initBaseInfo(roomIMStart, groupMemberService);

            // 设置游戏为进行中
            roomIMStart.setState(WsConstant.ROOM_STATE.STATE_ROOM_PLAYING);

            // 局数加1
            roomIMStart.setGameTimes(roomIMStart.getGameTimes() + 1);

            roomsMap.put(roomNum, roomIMStart);
            msgForRoom(RoomTool.getBackRoomByRoom(roomIMStart), WsConstant.TYPE_RM.TYPE_ROOM_START_BACK);
        } else if (roomIMStart.getRoomType() == 1) { // 5张
            // 格式化Room信息
            RoomTool.resetRoom(roomIMStart);

            // 合并入座人和游戏中的人
            RoomTool.createPlayers(roomIMStart);

            // 检查用户资格,不满足则剔除用户
            checkUserCoinsEnable(roomIMStart);

            // 判断有效用户数
            if (!checkStartEnable(roomIMStart)) {
                // 通知所有人
                msgForRoom(RoomTool.getBackRoomByRoom(roomIMStart), WsConstant.TYPE_RM.TYPE_ROOM_ALL_ERROR_BACK, "人数不足2人，不能开局!");

                // 临时
                roomIMStart.getPlayers().clear();
                roomsMap.put(roomNum, roomIMStart);
                msgForRoom(RoomTool.getBackRoomByRoom(roomIMStart), WsConstant.TYPE_RM.TYPE_ROOM_START_BACK);

                // 人数不足，删除房间
                deleteRoom(roomIMStart);
                return;
            }

            // 给玩家发底牌
            TexasIm.sendPersonCard(roomIMStart);

            // 无人位置处填充空数值
            RoomTool.addNullPlayer(roomIMStart);

            // 更新现有玩家
            RoomTool.refreshCanSpeakPlayerSeat(roomIMStart);

            // 全部设置为未说话
            RoomTool.setNoSpeak(roomIMStart);

            // 自动更新下一次询问位置
            RoomTool.startRecycle(roomIMStart);

            // 扣除 所有玩家的 积分
            RoomTool.initBaseInfoFor5Cards(roomIMStart, groupMemberService);

            // 设置游戏为进行中
            roomIMStart.setState(WsConstant.ROOM_STATE.STATE_ROOM_PLAYING);

            // 局数加1
            roomIMStart.setGameTimes(roomIMStart.getGameTimes() + 1);

            roomsMap.put(roomNum, roomIMStart);
            msgForRoom(RoomTool.getBackRoomByRoom(roomIMStart), WsConstant.TYPE_RM.TYPE_ROOM_START_BACK);
        }
    }

    private void doSee(RoomMsg room) {
        RoomIM roomIMForSee = roomsMap.get(room.getRoomNum());
        if (roomIMForSee.getRoomType() == 0) {
            // 更新玩家
            // 取出操作用户
            String seatNum = room.getBody();
            Player playerSee = roomIMForSee.getPlayers().get(seatNum);

            // 设置此玩家状态
            playerSee.setOptState(WsConstant.PLAYER_OPT.STATE_SEE_CARD);
            playerSee.setPlayState(WsConstant.PLAYER_PLAY.WAITING);
            playerSee.setHasSpeak(true);
            // 更新用户信息
            roomIMForSee.getPlayers().put(playerSee.getSeatNum(), playerSee);

            // 判断下一步操作
            nextStep(roomIMForSee, WsConstant.TYPE_RM.TYPE_ROOM_PLAYING_SEE_CARD);

        } else if (roomIMForSee.getRoomType() == 1) { // 5张
            // 更新玩家
            // 取出操作用户
            String seatNum = room.getBody();
            Player playerSee = roomIMForSee.getPlayers().get(seatNum);

            // 设置此玩家状态
            playerSee.setOptState(WsConstant.PLAYER_OPT.STATE_SEE_CARD);
            playerSee.setPlayState(WsConstant.PLAYER_PLAY.WAITING);
            playerSee.setHasSpeak(true);
            // 更新用户信息
            roomIMForSee.getPlayers().put(playerSee.getSeatNum(), playerSee);

            // 判断下一步操作
            nextStepFor5Cards(roomIMForSee, WsConstant.TYPE_RM.TYPE_ROOM_PLAYING_SEE_CARD);
        }
    }

    private void doFlow(RoomMsg room) {
        RoomIM roomIMForFlow = roomsMap.get(room.getRoomNum());
        if (roomIMForFlow.getRoomType() == 0) {
            // 获取操作参数

            // 取出操作用户
            String seatNum = room.getBody();
            Player playerFlow = roomIMForFlow.getPlayers().get(seatNum);

            // 算差值
            float thisCast = roomIMForFlow.getRoomCurrCast() - playerFlow.getPreCast();

            if (playerFlow.getOwnCoins() >= thisCast) {
                // 跟注人扣除投注积分
                float ownCoins = playerFlow.getOwnCoins() - thisCast;
                playerFlow.setOwnCoins(ownCoins);
                groupMemberService.updateUserCoins(roomIMForFlow.getRoomNum(), playerFlow.getAccount(), ownCoins);

                // 设置此玩家
                playerFlow.setOptState(WsConstant.PLAYER_OPT.STATE_FLOW);
                // 更新跟注人本局投出总值
                playerFlow.setPreAllCast(playerFlow.getPreAllCast() + thisCast);

                // 正常跟注后，将房间 此刻总投入 赋值给用户此刻总投入
                playerFlow.setPreCast(roomIMForFlow.getRoomCurrCast());

                // 更新房间池底
                roomIMForFlow.setBaseCoins(roomIMForFlow.getBaseCoins() + thisCast);
            } else {
                // 跟注人扣除投注积分
                float ownCoinsOld = playerFlow.getOwnCoins();
                float ownCoins = 0;
                playerFlow.setOwnCoins(ownCoins);
                groupMemberService.updateUserCoins(roomIMForFlow.getRoomNum(), playerFlow.getAccount(), ownCoins);

                // 设置此玩家
                playerFlow.setOptState(WsConstant.PLAYER_OPT.STATE_ALLIN);
                // 更新跟注人本局投出总值
                playerFlow.setPreAllCast(playerFlow.getPreAllCast() + ownCoinsOld);

                // 根据 此用户 之前投注 + 这次投注  和 房间当前投注值比较  判断房间处于什么状态
                playerFlow.setPreCast(playerFlow.getPreCast() + ownCoinsOld);

                // 更新房间池底
                roomIMForFlow.setBaseCoins(roomIMForFlow.getBaseCoins() + ownCoinsOld);
            }

            // 设置此玩家
            playerFlow.setHasSpeak(true);

            // 更新玩家信息
            roomIMForFlow.getPlayers().put(playerFlow.getSeatNum(), playerFlow);

            // 更新房间
            roomsMap.put(roomIMForFlow.getRoomNum(), roomIMForFlow);

            // 判断下一步操作
            nextStep(roomIMForFlow, WsConstant.TYPE_RM.TYPE_ROOM_PLAYING_FLOW_BACK);
        } else if (roomIMForFlow.getRoomType() == 1) { // 5张
            // 获取操作参数

            // 取出操作用户
            String seatNum = room.getBody();
            Player playerFlow = roomIMForFlow.getPlayers().get(seatNum);

            // 算差值
            float thisCast = roomIMForFlow.getRoomCurrCast() - playerFlow.getPreCast();

            if (playerFlow.getOwnCoins() >= thisCast) {
                // 跟注人扣除投注积分
                float ownCoins = playerFlow.getOwnCoins() - thisCast;
                playerFlow.setOwnCoins(ownCoins);
                groupMemberService.updateUserCoins(roomIMForFlow.getRoomNum(), playerFlow.getAccount(), ownCoins);

                // 设置此玩家
                playerFlow.setOptState(WsConstant.PLAYER_OPT.STATE_FLOW);
                // 更新跟注人本局投出总值
                playerFlow.setPreAllCast(playerFlow.getPreAllCast() + thisCast);

                // 正常跟注后，将房间 此刻总投入 赋值给用户此刻总投入
                playerFlow.setPreCast(roomIMForFlow.getRoomCurrCast());

                // 更新房间池底
                roomIMForFlow.setBaseCoins(roomIMForFlow.getBaseCoins() + thisCast);
            } else {
                // 跟注人扣除投注积分
                float ownCoinsOld = playerFlow.getOwnCoins();
                float ownCoins = 0;
                playerFlow.setOwnCoins(ownCoins);
                groupMemberService.updateUserCoins(roomIMForFlow.getRoomNum(), playerFlow.getAccount(), ownCoins);

                // 设置此玩家
                playerFlow.setOptState(WsConstant.PLAYER_OPT.STATE_ALLIN);
                // 更新跟注人本局投出总值
                playerFlow.setPreAllCast(playerFlow.getPreAllCast() + ownCoinsOld);

                // 根据 此用户 之前投注 + 这次投注  和 房间当前投注值比较  判断房间处于什么状态
                playerFlow.setPreCast(playerFlow.getPreCast() + ownCoinsOld);

                // 更新房间池底
                roomIMForFlow.setBaseCoins(roomIMForFlow.getBaseCoins() + ownCoinsOld);
            }

            // 设置此玩家
            playerFlow.setHasSpeak(true);

            // 更新玩家信息
            roomIMForFlow.getPlayers().put(playerFlow.getSeatNum(), playerFlow);

            // 更新房间
            roomsMap.put(roomIMForFlow.getRoomNum(), roomIMForFlow);

            // 判断下一步操作
            nextStepFor5Cards(roomIMForFlow, WsConstant.TYPE_RM.TYPE_ROOM_PLAYING_FLOW_BACK);
        }
    }

    private void doAdd(RoomMsg room) {
        RoomIM roomIMForAdd = roomsMap.get(room.getRoomNum());
        if (roomIMForAdd.getRoomType() == 0) {
            // 获取操作参数
            Player playerVo = JSON.parseObject(room.getBody(), Player.class);

            // 本次加注值
            float preAddCast = playerVo.getPreAddCast();

            // 取出内存用户
            Player playerAdd = roomIMForAdd.getPlayers().get(playerVo.getSeatNum());
            // 算差值
            float thisCast = roomIMForAdd.getRoomCurrCast() - playerAdd.getPreCast();
            if (thisCast > preAddCast) {
                String[] userAcc = new String[1];
                userAcc[0] = playerAdd.getAccount();
                errorMsgForSingle(userAcc, "加注值[" + preAddCast + "]不能小于跟注值[" + thisCast + "]");
                return;
            }

            if (preAddCast == playerAdd.getOwnCoins()) {
                // 加注值 等于 玩家所有值， 则将用户设置为 ALLIN
                playerAdd.setOptState(WsConstant.PLAYER_OPT.STATE_ALLIN);
            } else {
                playerAdd.setOptState(WsConstant.PLAYER_OPT.STATE_ADD);
            }

            playerAdd.setPlayState(WsConstant.PLAYER_PLAY.WAITING);

            // 加注人减去投注积分
            float ownCoins = playerAdd.getOwnCoins() - preAddCast;
            if (ownCoins < 0) {
                String[] userAcc = new String[1];
                userAcc[0] = playerAdd.getAccount();
                errorMsgForSingle(userAcc, "最多只能加注 " + playerAdd.getOwnCoins());
                return;
            }

            playerAdd.setOwnCoins(ownCoins);
            groupMemberService.updateUserCoins(roomIMForAdd.getRoomNum(), playerAdd.getAccount(), ownCoins);

            // 清空所有玩家的当前下注值及说话状态
            for (Player prePlayer : roomIMForAdd.getPlayers().values()) {
                if (prePlayer.getRunState() != WsConstant.PLAYER_RUN.empty && prePlayer.getOptState() != WsConstant.PLAYER_OPT.STATE_CANCEL && prePlayer.getOptState() != WsConstant.PLAYER_OPT.STATE_ALLIN) {
                    prePlayer.setPreCast(0);
                    prePlayer.setHasSpeak(false);
                }
            }
            // 更新加注人本局投出总值
            playerAdd.setHasSpeak(true);
            playerAdd.setPreAllCast(playerAdd.getPreAllCast() + preAddCast);
            playerAdd.setPreCast(preAddCast); // 设置个人本轮的询问值
            // 更新玩家信息
            roomIMForAdd.getPlayers().put(playerAdd.getSeatNum(), playerAdd);

            // 更新房间
            // 更新房间池底
            roomIMForAdd.setBaseCoins(roomIMForAdd.getBaseCoins() + preAddCast);
            // 设置房间本轮的询问值
            roomIMForAdd.setRoomCurrCast(preAddCast);

            roomsMap.put(roomIMForAdd.getRoomNum(), roomIMForAdd);

            // 判断下一步操作
            nextStep(roomIMForAdd, WsConstant.TYPE_RM.TYPE_ROOM_PLAYING_ADD_BACK);
        } else if (roomIMForAdd.getRoomType() == 1) { // 5张
// 获取操作参数
            Player playerVo = JSON.parseObject(room.getBody(), Player.class);

            // 本次加注值
            float preAddCast = playerVo.getPreAddCast();

            // 取出内存用户
            Player playerAdd = roomIMForAdd.getPlayers().get(playerVo.getSeatNum());
            // 算差值
            float thisCast = roomIMForAdd.getRoomCurrCast() - playerAdd.getPreCast();
            if (thisCast > preAddCast) {
                String[] userAcc = new String[1];
                userAcc[0] = playerAdd.getAccount();
                errorMsgForSingle(userAcc, "加注值[" + preAddCast + "]不能小于跟注值[" + thisCast + "]");
                return;
            }

            if (preAddCast == playerAdd.getOwnCoins()) {
                // 加注值 等于 玩家所有值， 则将用户设置为 ALLIN
                playerAdd.setOptState(WsConstant.PLAYER_OPT.STATE_ALLIN);
            } else {
                playerAdd.setOptState(WsConstant.PLAYER_OPT.STATE_ADD);
            }

            playerAdd.setPlayState(WsConstant.PLAYER_PLAY.WAITING);

            // 加注人减去投注积分
            float ownCoins = playerAdd.getOwnCoins() - preAddCast;
            if (ownCoins < 0) {
                String[] userAcc = new String[1];
                userAcc[0] = playerAdd.getAccount();
                errorMsgForSingle(userAcc, "最多只能加注 " + playerAdd.getOwnCoins());
                return;
            }

            playerAdd.setOwnCoins(ownCoins);
            groupMemberService.updateUserCoins(roomIMForAdd.getRoomNum(), playerAdd.getAccount(), ownCoins);

            // 清空所有玩家的当前下注值及说话状态
            for (Player prePlayer : roomIMForAdd.getPlayers().values()) {
                if (prePlayer.getRunState() != WsConstant.PLAYER_RUN.empty && prePlayer.getOptState() != WsConstant.PLAYER_OPT.STATE_CANCEL && prePlayer.getOptState() != WsConstant.PLAYER_OPT.STATE_ALLIN) {
                    prePlayer.setPreCast(0);
                    prePlayer.setHasSpeak(false);
                }
            }
            // 更新加注人本局投出总值
            playerAdd.setHasSpeak(true);
            playerAdd.setPreAllCast(playerAdd.getPreAllCast() + preAddCast);
            playerAdd.setPreCast(preAddCast); // 设置个人本轮的询问值
            // 更新玩家信息
            roomIMForAdd.getPlayers().put(playerAdd.getSeatNum(), playerAdd);

            // 更新房间
            // 更新房间池底
            roomIMForAdd.setBaseCoins(roomIMForAdd.getBaseCoins() + preAddCast);
            // 设置房间本轮的询问值
            roomIMForAdd.setRoomCurrCast(preAddCast);

            roomsMap.put(roomIMForAdd.getRoomNum(), roomIMForAdd);

            // 判断下一步操作
            nextStepFor5Cards(roomIMForAdd, WsConstant.TYPE_RM.TYPE_ROOM_PLAYING_ADD_BACK);
        }
    }

    private void giveUpCard(RoomMsg room) { // 弃牌
        RoomIM roomIMForCancel = roomsMap.get(room.getRoomNum());
        if (roomIMForCancel.getRoomType() == 0) {
            // 设置当前用户为弃牌
            String setNum = room.getSeatNum();
            Player playerCancel = roomIMForCancel.getPlayers().get(setNum);
            playerCancel.setOptState(WsConstant.PLAYER_OPT.STATE_CANCEL);
            playerCancel.setHasSpeak(true);
            playerCancel.setPlayState(WsConstant.PLAYER_PLAY.WAITING);
            // 更新玩家信息
            roomIMForCancel.getPlayers().put(playerCancel.getSeatNum(), playerCancel);

            ArrayList<Player> livePlayers = RoomTool.getLivePlayers(roomIMForCancel);

            if (livePlayers.size() > 1) {
                // 人数大于1，继续下一轮
                nextStep(roomIMForCancel, WsConstant.TYPE_RM.TYPE_ROOM_PLAYING_CANCEL_BACK);
            } else {
                if (livePlayers.size() == 1) {
                    // 设置最后一位赢TYPE_ROOM_RELEASE_BACK
                    roomIMForCancel.setWinner(livePlayers.get(0).getAccount());
                    RoomTool.setCompareResult(roomIMForCancel, groupMemberService);
                    roomIMForCancel.setGameOverType(3);

                    roomsMap.put(roomIMForCancel.getRoomNum(), roomIMForCancel);
                    msgForRoom(RoomTool.getBackRoomByRoom(roomIMForCancel), WsConstant.TYPE_RM.TYPE_ROOM_PLAYING_CANCEL_BACK);

                    // 开始下一轮
                    timerStart(roomIMForCancel);

                } else {
                    nextStep(roomIMForCancel, WsConstant.TYPE_RM.TYPE_ROOM_PLAYING_CANCEL_BACK);
                    log.error("异常============================================================================= livePlayers.size() = 0");
                }
            }

        } else if (roomIMForCancel.getRoomType() == 1) { // 5张

            // 设置当前用户为弃牌
            String setNum = room.getSeatNum();
            Player playerCancel = roomIMForCancel.getPlayers().get(setNum);
            playerCancel.setOptState(WsConstant.PLAYER_OPT.STATE_CANCEL);
            playerCancel.setHasSpeak(true);
            playerCancel.setPlayState(WsConstant.PLAYER_PLAY.WAITING);
            // 更新玩家信息
            roomIMForCancel.getPlayers().put(playerCancel.getSeatNum(), playerCancel);

            ArrayList<Player> livePlayers = RoomTool.getLivePlayers(roomIMForCancel);

            if (livePlayers.size() > 1) {
                // 人数大于1，继续下一轮
                nextStepFor5Cards(roomIMForCancel, WsConstant.TYPE_RM.TYPE_ROOM_PLAYING_CANCEL_BACK);
            } else {
                if (livePlayers.size() == 1) {
                    // 设置最后一位赢TYPE_ROOM_RELEASE_BACK
                    roomIMForCancel.setWinner(livePlayers.get(0).getAccount());
                    RoomTool.setCompareResult(roomIMForCancel, groupMemberService);
                    roomIMForCancel.setGameOverType(3);

                    roomsMap.put(roomIMForCancel.getRoomNum(), roomIMForCancel);
                    msgForRoom(RoomTool.getBackRoomByRoom(roomIMForCancel), WsConstant.TYPE_RM.TYPE_ROOM_PLAYING_CANCEL_BACK);

                    // 开始下一轮
                    timerStart(roomIMForCancel);
                } else {
                    nextStepFor5Cards(roomIMForCancel, WsConstant.TYPE_RM.TYPE_ROOM_PLAYING_CANCEL_BACK);
                    log.error("异常============================================================================= livePlayers.size() = 0");
                }
            }
        }
    }

    private void nextStep(RoomIM roomIM, int TYPE_RM) {

        boolean allCastEqual = true;
        boolean allHasSpeak = true;
        if (roomIM.getPlayers().size() == 0) {
            allHasSpeak = false;
            allCastEqual = false;
        }

        int playingNum = 0;
        int allinNum = 0;

        for (Player prePlayer : roomIM.getPlayers().values()) {
            if (prePlayer.getRunState() != WsConstant.PLAYER_RUN.empty && prePlayer.getOptState() != WsConstant.PLAYER_OPT.STATE_CANCEL) {
                if (prePlayer.getOptState() != WsConstant.PLAYER_OPT.STATE_ALLIN) {
                    // 计算 现有玩家 人数
                    playingNum += 1;

                    // 循环判断用户是否都说过话
                    if (!prePlayer.isHasSpeak()) {
                        allHasSpeak = false;
                    }

                    // 循环判断用户是否和最大投注相等
                    if (!(prePlayer.getPreCast() == roomIM.getRoomCurrCast())) {
                        allCastEqual = false;
                    }
                } else {
                    // 计算 allin 人数
                    allinNum += 1;
                }
            }
        }

        //每次都设置空，比牌后填入获胜者账号
        roomIM.setWinner("");

        // 只有一个正常玩家或没有正常玩家时      要细分  一开始就 Allin
        if (playingNum <= 1 && roomIM.getTexasPoker().getPublicPokerList() != null && roomIM.getTexasPoker().getPublicPokerList().size() != 5) {
            // 发放剩余底牌
            TexasIm.sendPubRemainingCards(roomIM);
            // 比牌
            TexasPokerCompare.compareForRoom(roomIM);
            // 计算，更新每个人的状态
            RoomTool.setCompareResult(roomIM, groupMemberService);
            roomsMap.put(roomIM.getRoomNum(), roomIM);
            msgForRoom(RoomTool.getBackRoomByRoom(roomIM), TYPE_RM);

            roomIM.setGameOverType(2);

            // 开始下一轮
            timerStart(roomIM);
            return;
        }

        // 正常情况
        if (allCastEqual && allHasSpeak) {// 所有人投注相等，并都说过话，就下一轮：发牌或比牌

            if (roomIM.getTexasPoker() != null && roomIM.getTexasPoker().getPublicPokerList() != null
                    && roomIM.getTexasPoker().getPublicPokerList().size() == 5) {
                roomIM.setGameOverType(0);
                // 最后一轮，则比牌
                TexasPokerCompare.compareForRoom(roomIM);

                log.error("比牌结果：" + JSON.toJSONString(roomIM));

                // 更新RoomIm并群发

                // 计算，更新每个人的状态
                RoomTool.setCompareResult(roomIM, groupMemberService);

                roomsMap.put(roomIM.getRoomNum(), roomIM);
                msgForRoom(RoomTool.getBackRoomByRoom(roomIM), TYPE_RM);

                // 开始下一轮
                timerStart(roomIM);
            } else {
                if (!roomIM.isHasSendPubCard()) {
                    // 没发公共牌，则此次就公共牌
                    TexasIm.sendPubCard(roomIM);
                } else {
                    // 已发公共牌，则此次只发一张
                    TexasIm.sendOneCard(roomIM);
                }

                initPlay(roomIM);

                // 不是最后一轮，发牌
                // 更新现有玩家
                RoomTool.refreshCanSpeakPlayerSeat(roomIM);
                // 自动更新下一次询问位置
                RoomTool.autoRecycle(roomIM);

                // 更新RoomIm并群发
                roomsMap.put(roomIM.getRoomNum(), roomIM);
                msgForRoom(RoomTool.getBackRoomByRoom(roomIM), TYPE_RM);
            }
        } else { // 自动下一位
            // 找出并更新现有玩家
            RoomTool.refreshCanSpeakPlayerSeat(roomIM);
            // 自动更新下一次询问位置
            RoomTool.autoRecycle(roomIM);

            // 更新RoomIm并群发
            roomsMap.put(roomIM.getRoomNum(), roomIM);
            msgForRoom(RoomTool.getBackRoomByRoom(roomIM), TYPE_RM);
        }
    }

    private void nextStepFor5Cards(RoomIM roomIM, int TYPE_RM) {
        boolean allCastEqual = true;
        boolean allHasSpeak = true;
        boolean userHasAllCards = true;

        if (roomIM.getPlayers().size() == 0) {
            allHasSpeak = false;
            allCastEqual = false;
        }

        int playingNum = 0;
        int allinNum = 0;
        for (Player prePlayer : roomIM.getPlayers().values()) {
            if (prePlayer.getRunState() != WsConstant.PLAYER_RUN.empty && prePlayer.getOptState() != WsConstant.PLAYER_OPT.STATE_CANCEL) {
                if (prePlayer.getOptState() != WsConstant.PLAYER_OPT.STATE_ALLIN) {
                    // 计算 现有玩家 人数
                    playingNum += 1;

                    // 循环判断用户是否都说过话
                    if (!prePlayer.isHasSpeak()) {
                        allHasSpeak = false;
                    }

                    // 循环判断用户是否和最大投注相等
                    if (!(prePlayer.getPreCast() == roomIM.getRoomCurrCast())) {
                        allCastEqual = false;
                    }
                } else {
                    // 计算 allin 人数
                    allinNum += 1;
                }

                // 判断每个用户的手上牌数
                if (prePlayer.getUserPokers() == null || prePlayer.getUserPokers().size() != 5) {
                    userHasAllCards = false;
                }
            }
        }

        //每次都设置空，比牌后填入获胜者账号
        roomIM.setWinner("");

//        // 只有一个正常玩家或没有正常玩家时      要细分  一开始就 Allin
//        if (playingNum <= 1 && roomIM.getTexasPoker().getPublicPokerList() != null && roomIM.getTexasPoker().getPublicPokerList().size() != 5) {
//            // 发放剩余底牌
//            TexasIm.sendPubRemainingCards(roomIM);
//            // 比牌
//            TexasPokerCompare.compareForRoom(roomIM);
//            // 计算，更新每个人的状态
//            RoomTool.setCompareResult(roomIM, groupMemberService);
//            roomsMap.put(roomIM.getRoomNum(), roomIM);
//            msgForRoom(RoomTool.getBackRoomByRoom(roomIM), TYPE_RM);
//
//            roomIM.setGameOverType(2);
//
//            // 开始下一轮
//            timerStart(roomIM);
//            return;
//        }

        // 正常情况
        if (allCastEqual && allHasSpeak) {// 所有人投注相等，并都说过话，就下一轮：发牌或比牌

            if (roomIM.getTexasPoker() != null && userHasAllCards) { // 每个正常玩家都是5张，则比牌
                roomIM.setGameOverType(0);
                // 最后一轮，则比牌
                TexasPokerCompare.compareForRoomFor5Cards(roomIM);
                log.error("比牌结果：" + JSON.toJSONString(roomIM));

                // 更新RoomIm并群发
                // 计算，更新每个人的状态
                RoomTool.setCompareResultFor5Cards(roomIM, groupMemberService);

                roomsMap.put(roomIM.getRoomNum(), roomIM);
                msgForRoom(RoomTool.getBackRoomByRoom(roomIM), TYPE_RM);

                // 开始下一轮
                timerStart(roomIM);
            } else {
                // 给每个玩家发一张牌
                TexasIm.sendOneCardToPrePlayer(roomIM);

                initPlay(roomIM);

                // 不是最后一轮，发牌
                // 更新现有玩家
                RoomTool.refreshCanSpeakPlayerSeat(roomIM);
                // 自动更新下一次询问位置
                RoomTool.autoRecycle(roomIM);

                // 更新RoomIm并群发
                roomsMap.put(roomIM.getRoomNum(), roomIM);
                msgForRoom(RoomTool.getBackRoomByRoom(roomIM), TYPE_RM);
            }
        } else { // 自动下一位
            // 找出并更新现有玩家
            RoomTool.refreshCanSpeakPlayerSeat(roomIM);
            // 自动更新下一次询问位置
            RoomTool.autoRecycle(roomIM);

            // 更新RoomIm并群发
            roomsMap.put(roomIM.getRoomNum(), roomIM);
            msgForRoom(RoomTool.getBackRoomByRoom(roomIM), TYPE_RM);
        }
    }
}
